/**
 * 
 */
package com.redsoft.spirit.service;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.redsoft.spirit.dao.DeptRepository;
import com.redsoft.spirit.entity.Department;
import com.redsoft.spirit.entity.TreeNode;
import com.redsoft.spirit.util.BeanUtils;

/**
 * 部门管理的Service
 * 
 * <pre>
 * 部门管理的Service
 * </pre>
 * 
 * @author 杨雷
 * @since 1.0
 */
@Service
@Transactional
public class DeptService {

	@Resource
	private DeptRepository deptRepository;

	@Value("${jdbc.db-type}")
	private String dbType;

	@Cacheable(value = "dept-cache", key = "'dept-cache'+#userId")
	public List<TreeNode> getJsonTree(String userId) {

		// //先查询本系统中最顶级的部门，相当于0级，一般在数据库写死
		// Department dept = deptRepository.getByDeptLevel(0);
		//
		// TreeNode tree = tree(dept);
		// List<TreeNode> list = new ArrayList<TreeNode>();
		// list.add(tree);
		// return list;

		List<TreeNode> trees = new ArrayList<TreeNode>();

		// 先查询出所有的码表项，然后遍历，创建出对应的treeNode项
		// 如果是 超级管理员则查询全部，如果不是则查询这个人所拥有的所有菜单
		List<Department> depts = new ArrayList<>();

		if ("10000".equals(userId)) {
			// String sql = "SELECT * FROM sys_department d WHERE
			// FIND_IN_SET(id,getSonDept(1)) and d.is_active = 1";
			String deptId = "0";
			String sql = "";
			// 如果是mysql的话，则使用存储过程完成这段返回树形结构的数据
			if ("mysql".equals(dbType.toLowerCase())) {
				
				sql = "call p_dept_path(?)";
				depts = deptRepository.sqlQuery(sql, deptId);
			} else if ("oracle".equals(dbType.toLowerCase())) {
				
				sql = "select * "
						+ " from sys_department "
						+ " where 1 = 1 "
//						+ " and is_active = '1' "
						+ " start with id = '1' connect by prior id = PARENT_DEPT_ID "
						+ " order by display_order asc ";
				depts = deptRepository.sqlQuery(sql);
			} else if ("sqlserver".equals(dbType.toLowerCase())) {
				
				sql = " with dept_temp as "
						+ " ( select *,0 AS LevelID "
						+ " from sys_department "
						+ " WHERE id=  '1' "
						+ " UNION ALL "
						+ " SELECT a.*,(LevelID + 1) AS LevelID "
						+ " from sys_department a "
						+ " INNER JOIN dept_temp b "
						+ " ON a.PARENT_DEPT_ID = b.id "
						+ " where 1 = 1 "
//						+ " and a.is_active = '1' "
						+ " order by a.display_order asc) "
						+ " SELECT * FROM dept_temp";
				depts = deptRepository.sqlQuery(sql);
			}
			trees = initTree(depts);
		} else {
			depts = deptRepository.getDeptsByUserId(userId);

			// 如果这个人有多个部门，则遍历出来,并根据这个部门查询下面所有的子部门，然后创建trees
			for (Department department : depts) {
				String sql = "";

				// 如果是mysql的话，则使用存储过程完成这段返回树形结构的数据
				if ("mysql".equals(dbType.toLowerCase())) {
					
					sql = "call p_dept_path(?)";
				} else if ("oracle".equals(dbType.toLowerCase())) {
					
					sql = " select * "
							+ " from sys_department "
							+ " where 1 = 1 "
//							+ " and is_active = '1' "
							+ " start with id = ? connect by prior id = PARENT_DEPT_ID "
							+ " order by display_order asc ";
				} else if ("sqlserver".equals(dbType.toLowerCase())) {
					
					sql = " with dept_temp as "
							+ " ( select *,0 AS LevelID "
							+ " from sys_department WHERE id=  ? "
							+ " UNION ALL"
							+ " SELECT a.*,(LevelID + 1) AS LevelID "
							+ " from sys_department a "
							+ " INNER JOIN dept_temp b "
							+ " ON a.PARENT_DEPT_ID = b.id "
							+ " where 1 = 1 "
//							+ " and a.is_active = '1' "
							+ " order by a.display_order asc) "
							+ " SELECT * FROM dept_temp ";
				}
				List<Department> deptChilds = deptRepository.sqlQuery(sql, department.getId());

				if ("mysql".equals(dbType.toLowerCase())) {

					// 因为这个存储过程是只查询子孙级的，不包含自己，所以需要给自己加进去。
					department.setIsRoot(1);
					deptChilds.add(department);
				} else {
					// 取当前的根节点部门，给设置上是根的标记
					deptChilds.get(0).setIsRoot(1);
				}

				List<TreeNode> treeChilds = initTree(deptChilds);
				trees.addAll(treeChilds);
			}
		}
		return trees;
	}

	private List<TreeNode> initTree(List<Department> depts) {
		List<TreeNode> trees = new ArrayList<>();
		Map<String, TreeNode> map = new HashMap<>();

		for (Department dept : depts) {
			TreeNode node = new TreeNode();
			node.setId(dept.getId());
			node.setLabel(dept.getName());
			node.setChildren(new ArrayList<TreeNode>());
			node.setParentId(dept.getParentDeptId());
			node.setRoot(dept.getIsRoot());
			node.setIsActive(dept.getIsActive());
			
			map.put(node.getId(), node);
		}

		// 当dept的parentId从
		// map中可以获取到时候，把这个dept对应的map中的node取出来，放到parentId的node的children中
		for (Department dept : depts) {
			if (map.containsKey(dept.getParentDeptId())) {
				map.get(dept.getParentDeptId()).getChildren().add(map.get(dept.getId()));
				// map.remove(codeTable.getId());
			}
		}

		for (TreeNode treeNode : map.values()) {
			if ("0".equals(treeNode.getParentId())) {
				trees.add(treeNode);
			} else {
				if (treeNode.getRoot() != null && treeNode.getRoot() == 1) {
					trees.add(treeNode);
				}
			}
		}
		return trees;
	}

	/**
	 * 用递归来完成这个组织结构树的构建
	 * 
	 * <pre>
	 * 用递归来完成这个组织结构树的构建
	 * </pre>
	 * 
	 * @author 杨雷
	 * @param tree
	 * @param dept
	 * @return
	 */
	private TreeNode tree(Department dept) {

		TreeNode tree = new TreeNode();
		tree.setId(dept.getId());
		tree.setIsActive(dept.getIsActive());
		tree.setLabel(dept.getName());
		tree.setDisplayOrder(dept.getDisplayOrder());

		List<Department> depts = deptRepository.getByParentDeptId(dept.getId());
		List<TreeNode> children = new ArrayList<>();
		TreeNode treeNodeTemp;

		for (Department department : depts) {
			treeNodeTemp = tree(department);
			children.add(treeNodeTemp);
		}
		tree.setChildren(children);
		return tree;
	}

	/**
	 * 保存部门
	 * 
	 * <pre>
	 * 保存新部门
	 * </pre>
	 * 
	 * @author 杨雷
	 * @param dept
	 * @param userId
	 * @throws Exception
	 * @throws InvocationTargetException
	 * @throws IllegalAccessException
	 */
	@CacheEvict(value = { "dept-cache" }, key = "'dept-cache'+#userId", allEntries = true, beforeInvocation = true)
	public void saveOrUpdate(Department dept, String userId) throws Exception {
		if (!"".equals(dept.getId())) {
			Department deptTemp = deptRepository.getById(dept.getId());
			BeanUtils.copyBeanNotNull2Bean(dept, deptTemp);
			deptRepository.save(deptTemp);
		} else {
			deptRepository.save(dept);
		}
	}

	/**
	 * 查询部门
	 * 
	 * <pre>
	 * 查询部门以及上级部门名称
	 * </pre>
	 * 
	 * @author 杨雷
	 * @param id
	 * @return
	 */
	public Department get(String id) {
		
//		String sql = "select d2.*, d1.name as parentDeptName from sys_department d1 , sys_department d2 where d1.id = d2.parent_dept_id and d2.id = ?";
		String sql = "SELECT d1.*, 	d2.name AS parentDeptName "
				+ " FROM sys_department d1 "
				+ " left join	sys_department d2 "
				+ " on d2.id = d1.parent_dept_id "
				+ " WHERE d1.id = ? ";
		return deptRepository.sqlQuery(sql, id).get(0);
	}

	/**
	 * 查询所有已经启用的部门，除了本部
	 * 
	 * <pre>
	 * 	查询所有已经启用的部门，除了本部
	 * </pre>
	 * 
	 * @author 杨雷
	 * @return
	 */
	public List<Department> getDeptList() {
		return deptRepository.getByIdNotAndIsActive("1", 1);
	}

	/**
	 * 根据用户id查询部门
	 * 
	 * <pre>
	 * 根据用户id查询部门
	 * </pre>
	 * 
	 * @author 杨雷
	 * @param id
	 * @return
	 */
	public Department getDeptByUserId(String id) {
		return deptRepository.getDeptByUserId(id);
	}

	/**
	 * 获取园区服务部门信息
	 * 
	 * <pre>
	 * 获取园区服务部门信息
	 * </pre>
	 * 
	 * @author 杨雷
	 * @return
	 */
	public List<Department> getServiceDept() {
		return deptRepository.getServiceDept();
	}

	/**
	 * 根据父级id获取部门id
	 */
	public List<Department> getDeptByParentDeptId(String id) {
		return deptRepository.getDeptByParentDeptId(id);
	}

	/**
	 * 删除部门
	 * 
	 * <pre>
	 * 删除部门，给状态设置为停用
	 * </pre>
	 * 
	 * @author 杨雷
	 * @param id
	 */
	public void deleteDept(String id) {
		deptRepository.deleteDept(id);
	}
	
	/**
	 * 
	 * 已停用部门重新启用
	 * <pre>
	 * 已停用部门重新启用
	 * </pre>
	 * 
	 * @author lixiaodong
	 * @param id
	 */
	public void recoverDept(String id) {
		Department dept = deptRepository.getById(id);
		//重新启用
		dept.setIsActive(1);
		deptRepository.save(dept);
	}
}
